package net.shakewarner;

import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.shakewarner.dao.MeasurementDao;
import net.shakewarner.dao.impl.MeasurementDaoImpl;
import net.shakewarner.entity.Measurement;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;

/**
 * definition of service that accepts and delivers measurements. Typical
 * requests:
 * 
 * -------- Save measurements -------- <br/>
 * URL: http://localhost:8888/shake_warner_service <br/>
 * method: POST body: [{"latitude":"11.11"
 * ,"longtitude":"222.22","time":1303931546730,"direction":12,"shakeLevel":4},
 * {"latitude"
 * :"22.22","longtitude":"333.33","time":1303931548888,"direction":11,
 * "shakeLevel":11}] * Body is the list representing posted measurements.
 * 
 * -------- Load measurements -------- <br/>
 * URL: http://localhost:8888/shake_warner_service <br/>
 * method: GET
 * 
 * @author public
 * 
 */
@SuppressWarnings("serial")
public class ShakeWarnerServiceServlet extends HttpServlet {

	private final MeasurementDao measurementDao = new MeasurementDaoImpl();

	@Override
	public void doGet(final HttpServletRequest req,
			final HttpServletResponse resp) throws IOException {

		resp.setContentType("text/plain");

		final String measurements = getJsonMeasurements();
		resp.getWriter().write(measurements);
	}

	@Override
	protected void doPost(final HttpServletRequest req,
			final HttpServletResponse resp) throws ServletException,
			IOException {

		final BufferedReader reader = req.getReader();

		final Collection<Measurement> input = new ArrayList<Measurement>();
		final ReturnCode returnCode = parseMeasurements(reader, input);

		this.measurementDao.saveAll(input);

		resp.setContentType("text/plain");
		resp.getWriter().write(returnCode.getRepresentation());
	}

	/**
	 * reads and adds measurements to specified collection. Collection is not
	 * cleared before filling
	 * 
	 * @param reader
	 *            source to read
	 * @param measurements
	 *            collection to fill
	 * 
	 * @return result of processing
	 */
	private static ReturnCode parseMeasurements(final BufferedReader reader,
			final Collection<Measurement> measurements) {
		ReturnCode res = ReturnCode.NONE;

		if ((reader == null) || (measurements == null)) {
			return res;
		}

		String json = "";
		String line = "";
		while (line != null) {
			json += line;

			try {
				line = reader.readLine();
			} catch (final IOException e) {
				e.printStackTrace();
				res = ReturnCode.READ_ERROR;
			}
		}

		final Gson gson = new Gson();
		final Type collectionType = new TypeToken<Collection<Measurement>>() {
		}.getType();

		try {
			final Object fromJson = gson.fromJson(json, collectionType);
			if (fromJson instanceof Collection<?>) {

				@SuppressWarnings("unchecked")
				final Collection<Measurement> col = (Collection<Measurement>) fromJson;
				measurements.addAll(col);

				res = ReturnCode.SUCCESS;
			}
		} catch (final JsonSyntaxException e) {
			e.printStackTrace();
			res = ReturnCode.PARSE_ERROR;
		}

		return res;
	}

	/**
	 * retrieve actual measurements in json format
	 * 
	 * @return measurements
	 */
	private String getJsonMeasurements() {
		String res = "";

		final Collection<Measurement> list = this.measurementDao.list();

		final Gson gson = new GsonBuilder()
				.excludeFieldsWithoutExposeAnnotation().create();

		res = gson.toJson(list);

		return res;
	}
}
